﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace SpaceWars
{
    public class Sprite{
        public Texture2D sprite;
        public Vector2 loc, vel, size, origin;
        public double angle;
        public bool alive;
        public Vector2 SCREEN_SIZE;
        
        public Sprite( Vector2 screen ){
            sprite = null;
            loc = new Vector2(-500.0f, -500.0f);
            vel = size = origin = Vector2.Zero;
            angle = 0.0;
            alive = false;
            SCREEN_SIZE = screen;
        }

        public Sprite( Vector2 screen, Texture2D texture){
            sprite = texture;
            loc = new Vector2(-500.0f, -500.0f);
            vel = size = origin = Vector2.Zero;
            angle = 0.0;
            alive = false;
            SCREEN_SIZE = screen;
        }
        public Sprite( Vector2 screen, Texture2D texture, Vector2 location, Vector2 velocity,
                       Vector2 spriteSize, Vector2 spriteCenter, double rotation,
                       bool isAlive){
            sprite = texture;
            loc = location;
            vel = velocity;
            size = spriteSize;
            origin = spriteCenter;
            angle = rotation;
            alive = isAlive;
            SCREEN_SIZE = screen;
        }

        public virtual void update( double elapsedTime ){
            loc += vel * (float)elapsedTime;
        }
        public virtual void draw(SpriteBatch sb){
            sb.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
                sb.Draw(sprite, loc, new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White,
                        (float)angle, origin, 1.0f, SpriteEffects.None, 0.5f);
            sb.End();
        }
        public bool collides(Sprite that){
            if (!this.alive || !that.alive)
                return false;
            Rectangle thisBox = new Rectangle((int)(loc.X-origin.X), (int)(loc.Y-origin.Y), (int)size.X, (int)size.Y);
            Rectangle thatBox = new Rectangle((int)(that.loc.X-that.origin.X), (int)(that.loc.Y-that.origin.Y), (int)that.size.X, (int)that.size.Y);
            return thisBox.Intersects(thatBox);
        }
        public void kill(){
            alive = false;
            loc = new Vector2(-500.0f, -500.0f);
            vel = Vector2.Zero;
        }
    }

    public class PlayerShip: Sprite{
        public int bulletsLeft, maxBullets;
        public int health;

        public PlayerShip(Vector2 screen) : base( screen ) { maxBullets = bulletsLeft = 100; health = 4; }
        public PlayerShip(Vector2 screen, Texture2D texture) : base( screen, texture ) { maxBullets = bulletsLeft = 100; health = 4; }
        public PlayerShip(Vector2 screen, Texture2D texture, Vector2 location, Vector2 velocity,
                          Vector2 spriteSize, Vector2 spriteCenter, double rotation, bool isAlive) :
                          base(screen, texture, location, velocity, spriteSize, spriteCenter, rotation, isAlive)
        { maxBullets = bulletsLeft = 100; health = 4; }
        public PlayerShip(Vector2 screen, Texture2D texture, Vector2 location, Vector2 velocity, Vector2 spriteSize, 
                          Vector2 spriteCenter, double rotation, bool isAlive, int bullets, int hp) :
                          base( screen, texture, location, velocity, spriteSize, spriteCenter, rotation, isAlive)
        { maxBullets = bulletsLeft = bullets; health = hp; }

        public override void update(double elapsedTime){
            if (vel.Length() >= 300.0f)
                vel *= 300.0f / vel.Length();
            vel *= 0.875f;
            base.update(elapsedTime);
            if (loc.X <= origin.X)
                loc.X = origin.X;
            if (loc.Y <= origin.Y)
                loc.Y = origin.Y;
            if (loc.X >= SCREEN_SIZE.X-origin.X)
                loc.X = SCREEN_SIZE.X-origin.X;
            if (loc.Y >= SCREEN_SIZE.Y-origin.Y)
                loc.Y = SCREEN_SIZE.Y-origin.Y;
        }
        public override void draw(SpriteBatch sb){
            float bulletPercent = (float)bulletsLeft / (float)maxBullets;
            Vector3 clr = new Vector3(1.0f, bulletPercent, bulletPercent);
            Color color = new Color(clr);
            sb.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
                sb.Draw(sprite, loc, new Rectangle(0, 0, (int)size.X, (int)size.Y), color, 
                        (float)angle, origin, 1.0f, SpriteEffects.None, 0.5f);
            sb.End();
        }
    }

    public class Enemy : Sprite
    {
        public int type;
        protected int status;
        public Enemy(Vector2 screen) : base(screen) { type = 1; }
        public Enemy(Vector2 screen, Texture2D texture) : base(screen, texture) { type = 1; }
        public Enemy(Vector2 screen, Texture2D texture, Vector2 location, Vector2 velocity,
                          Vector2 spriteSize, Vector2 spriteCenter, double rotation, bool isAlive) :
            base(screen, texture, location, velocity, spriteSize, spriteCenter, rotation, isAlive)
        { type = 1; }
        public Enemy(Vector2 screen, Texture2D texture, Vector2 location, Vector2 velocity, Vector2 spriteSize,
                          Vector2 spriteCenter, double rotation, bool isAlive, int typeNum) :
            base(screen, texture, location, velocity, spriteSize, spriteCenter, rotation, isAlive)
        { type = typeNum; status = 0; }
        public override void update(double elapsedTime)
        {
            if (type == 2){    // Circle the screen
                if (status==0){ // If it isn't orbiting, move it towards the start point
                    Vector2 tmp = new Vector2(3.0f / 4.0f * SCREEN_SIZE.X, SCREEN_SIZE.Y / 2.0f);
                    tmp -= loc;
                    tmp *= 75.0f / tmp.Length();
                    if (tmp.Y == 0)
                        angle = Math.PI / 2.0 - Math.Sign(tmp.X) * Math.PI / 2.0;
                    else{
                        if (tmp.X > 0)
                            angle = -Math.Atan(tmp.Y / tmp.X);
                        else
                            angle = Math.PI + Math.Atan(tmp.Y / tmp.X);
                    }
                    vel = tmp;
                    status = 1;
                }
                if (status == 1){
                    Vector2 tmp = new Vector2(3.0f / 4.0f * SCREEN_SIZE.X, SCREEN_SIZE.Y / 2.0f);
                    tmp -= loc;
                    if (tmp.Length() <= 2.0f){
                        status = 2;
                        angle = -Math.PI / 2.0;
                        vel = new Vector2(0.0f, -50.0f);
                    }
                }
                if( status == 2 ){   // It is orbiting, make it circle based on angle
                    angle -= Math.PI / 12 * elapsedTime;
                    Vector2 tmp = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
                    tmp *= 72.5f;
                    vel = tmp;
                }
            }
            base.update(elapsedTime);
        }
    }

    public class Background : Sprite{
        public Background(Vector2 screen) : base(screen) { }
        public Background(Vector2 screen, Texture2D texture ): 
            base( screen, texture, screen/2.0f, Vector2.Zero, screen,
                  screen/2.0f, 0.0, true ){}
        public override void update(double elapsedTime){
            float tmp = vel.Length();
            // Limit maximum speed to 200 pixels per second
            if (tmp > 200.0f)
                vel *= (200.0f / tmp);
            vel *= 0.9f;
            loc += vel * (float)elapsedTime;
            if (loc.Y >= SCREEN_SIZE.Y)
                loc.Y = 0.0f;
            if (loc.Y <= -SCREEN_SIZE.Y / 2.0f)
                loc.Y = SCREEN_SIZE.Y / 2.0f;
            if (loc.X >= SCREEN_SIZE.X)
                loc.X = 0.0f;
            if (loc.X <= -SCREEN_SIZE.X / 2.0f)
                loc.X = SCREEN_SIZE.X / 2.0f;
        }
        public override void draw(SpriteBatch sb){
            sb.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
            sb.Draw(sprite, loc, new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(size.X, 0.0f), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(size.X, size.Y), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(size.X, -size.Y), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(-size.X, 0.0f), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(-size.X, size.Y), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(-size.X, -size.Y), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(0.0f, size.Y), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.Draw(sprite, loc - new Vector2(0.0f, -size.Y), new Rectangle(0, 0, (int)size.X, (int)size.Y), Color.White, (float)angle, size / 2.0f, 1.0f, SpriteEffects.None, 0.0f);
            sb.End();
        }
    }
}
